package vek.Update;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import util.FileGetter;
import vek.Main2;
import vek.ObjectDatabase.DatabaseConnector;
import vek.Objects.POI;
import vek.TerminalSettings;
import vek.XML.Parsers.XMLParserMain;
import vek.XML.parsedObjects.ParsedObjectInterface;

/**
 * This class updates the XML files.
 * Updates the XML files by first downloading the update.xml file which specifes which files to download.
 * Then it downloads the files and compares them based on the file names which contain the dates they were updated.
 * If the files on the server are newer, they are then downloaded and parsed and the databases are then updated.
 * @author Christian, Michal og Jakob (Hold 1, gruppe 2)
 */
public class Updater extends TimerTask{
    
    private DatabaseConnector databaseConnector;
    public enum UpdateType { SIMPLEDATABASE }
    
    public void run()
    {
        System.out.println("Schedueled update has run...");
        update(TerminalSettings.getPathToXMLFiles(), TerminalSettings.getPathToUpdateFile());
    }
    
    /**
     * 
     * @param dbc the database connector which the update will be chanelled to
     */
    
    public Updater(DatabaseConnector dbc)
    {
        databaseConnector = dbc;
    }
    
    /**
     * Updates the POIs based on the update.xml file on the server.
     * 
     * @param pathToXMLFiles the URL to the XML files on the server
     * @param pathToUpdateXML the path(URL) to the XML file which contains a list of the XML files on the server
     */
    
    public void update(String pathToXMLFiles, String pathToUpdateXML)
    {
        ArrayList<String> listOfXMLFilesOnServer = XMLParserMain.parseUpdateXML(pathToUpdateXML);
        
        if(listOfXMLFilesOnServer == null)
        {
            System.err.println("Could not download update file, internet possibly down or path to update file is wrong");
        }
        else
        {
            ArrayList<String> filesInUpdateDirectory = FileGetter.getXMLFilesInUpdateDirectory();
        
            ArrayList<Date> datesOfXMLFilesFromServer = getDatesOfFilesInDirectory(listOfXMLFilesOnServer);
            ArrayList<Date> datesOfFilesInUpdateDirectory = getDatesOfFilesInDirectory(filesInUpdateDirectory);
        
            ArrayList<String> justNamesOfFilesInUpdateDirectory = getJustNamesOfXMLFiles(filesInUpdateDirectory);
            ArrayList<String> justNamesOfFilesOnServer = getJustNamesOfXMLFiles(listOfXMLFilesOnServer);
        
            ArrayList<ArrayList<String>> filesToBeDownloadedAndDeleted = getFilesToBeDownloadedAndDeleted(pathToXMLFiles, listOfXMLFilesOnServer, filesInUpdateDirectory, justNamesOfFilesInUpdateDirectory,justNamesOfFilesOnServer, datesOfFilesInUpdateDirectory, datesOfXMLFilesFromServer);
        
            downloadFilesAndDeleteFiles(filesToBeDownloadedAndDeleted.get(0), filesToBeDownloadedAndDeleted.get(1), pathToXMLFiles);
        
            System.out.println(filesToBeDownloadedAndDeleted.get(0).size() + " files updates, " + filesToBeDownloadedAndDeleted.get(1).size() + " files deleted");
        
            if(filesToBeDownloadedAndDeleted.get(0).size() != 0 && filesToBeDownloadedAndDeleted.get(1).size() != 0)
            {
            parseXMLFilesAndAddToDatabase();  
            }
            
        }
        
        
        
        
    }
    
    /**
     * Uses the parsers to parse the XML files and then adds them to the databases
     * using the updateSimpleDatabases() method in the DatabaseConnector
     */
    
    private void parseXMLFilesAndAddToDatabase()
    {
        System.out.println("Database updated");
        ArrayList<ArrayList<ParsedObjectInterface>> parsedObjects = Main2.parseXMLFilesAndReturnParsedObjects(FileGetter.getUpdateDirectory());
        ArrayList<POI> allPOIObjects = Main2.createPOIObjects(parsedObjects); 
        databaseConnector.updateSimpleDatabases(allPOIObjects);
    }
    
    /**
     * Downloads the new XML files which are to be parsed and deleted the local files which are replace by the newer files (that is the ones who are older and of the same type as the new files)
     * @param filesToBeDownloaded file names of the files which are to be downloaded
     * @param filesToBeDeleted the file names of the files which are to be deleted
     * @param pathToXMLFiles the path(URL) to the files which are to be downloaded
     */
    
    private void downloadFilesAndDeleteFiles(ArrayList<String> filesToBeDownloaded, ArrayList<String> filesToBeDeleted, String pathToXMLFiles)
    {
        // download the files and return a list of files which could not be downloaded
        ArrayList<String> filesWhichCouldNotBeDownloaded = FileGetter.downloadXMLFilesToUpdateDirectory(pathToXMLFiles, filesToBeDownloaded);
        
        // remove the files which could not be downloaded from the list so that the local copy is going to be used
        ArrayList<String> filesToBeDeletedWithoutLocalCopiesThatFailedToDownload = CheckIfFilesHaveNotBeenDownloadedReturnNewListDeletedFiles(filesWhichCouldNotBeDownloaded, filesToBeDeleted);
        
        // delete all the old files of which a newer version has been downloaded successfully
        FileGetter.deleteXMLFilesInUpdateDirectory(filesToBeDeletedWithoutLocalCopiesThatFailedToDownload);
    }
    
    /**
     * This method returns a modified list of the files to be deleted.
     * The files which correspond to the files which could not be downloaded are removed from the delete list.
     * Thus if a newer version of the file Museum was originally to be downloaded but something went wrong, 
     * the old local copy is rained rather than being deleted.
     * 
     * @param filesWhichCouldNotBeDownloaded the file names of the files which could not be downloaded (most likely due to lack of internet or wrong path/file name)
     * @param filesToBeDeleted the complete list of files which are to be deleted
     * @return the modified list of files to be deleted, where the ones that of the same type as the files that could not be downloaded are removed.
     */
    
    private ArrayList<String> CheckIfFilesHaveNotBeenDownloadedReturnNewListDeletedFiles(ArrayList<String> filesWhichCouldNotBeDownloaded, ArrayList<String> filesToBeDeleted)
    {
        ArrayList<String> justNamesOfFilesWhichCouldNotBeDownloaded = getJustNamesOfXMLFiles(filesWhichCouldNotBeDownloaded);
        ArrayList<String> justNamesOfFilesToBeDeleted = getJustNamesOfXMLFiles(filesToBeDeleted);
        
        for(int i = 0; i < filesWhichCouldNotBeDownloaded.size(); i++)
        {
            int index = justNamesOfFilesToBeDeleted.indexOf(justNamesOfFilesWhichCouldNotBeDownloaded.get(i));
            filesToBeDeleted.remove(index);
        }
        
        return filesToBeDeleted;
    }
    
    /**
     * gets the file names of the XML files, that is just file names not the path and the file name
     * @param files the file names and paths to the XML files which are to be downloaded
     * @return the file names of the XML files
     */
    
    private ArrayList<String> getJustNamesOfXMLFiles(ArrayList<String> files)
    {
        ArrayList<String> returnedJustNames = new ArrayList<String>();
        
        for(int n = 0; n < files.size(); n++)
        {
            returnedJustNames.add( files.get(n).substring(files.get(n).lastIndexOf(System.getProperty("file.separator")) + 1, files.get(n).indexOf("_")) );
        }
        
        return returnedJustNames;
    }
    
    /**
     * Gets the dates of the files based on the file names.
     * The date format is thus: yyyy-MM-dd-hh-mm-ss
     * example: 2008-01-02-03-04-05 == the 2nd of Jan, 2008, 3 hours, 4 minutes and 5 seconds. 
     * @param al the file names which contains dates
     * @return the dates in the file names converted to the type Date.
     */
    
    private ArrayList<Date> getDatesOfFilesInDirectory(ArrayList<String> al)
    {
        ArrayList<Date> returnedDates = new ArrayList<Date>();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");  // date format is in ISO standard format
                                                                                // year-month-day-hour-minute-second
                                                                                // year is 4 digits, hours are 24 hours.
        for(int i = 0; i < al.size(); i++)
        {
            try { 
                returnedDates.add( format.parse(al.get(i).substring(al.get(i).indexOf("_") + 1, al.get(i).indexOf("."))) );
            } 
            catch (ParseException ex) 
            {
                Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        return returnedDates;
    }
    
    /**
     * Gets the files to be downloaded and deleted.
     * @param pathToServer the path(URL) to the server
     * @param listOfXMLFilesOnServer the file names of the XML files on the server
     * @param filesInUpdateDirectory the files names of the files in the update directory
     * @param justNamesOfFilesInUpdateDirectory just the names, that is excluding the dates of the files in the update directory
     * @param justNamesOfFilesOnServer just the names, that is excluding the dates, of the files on the server
     * @param datesOfFilesInUpdateDirectory the dates of the files on the update server
     * @param datesOfXMLFiles the dates of the files in the update directory
     * @return an ArrayList containing 2 ArrayLists: first the list of files to be downloaded, second the list of files to be deleted.
     */
    
    public ArrayList<ArrayList<String>> getFilesToBeDownloadedAndDeleted(String pathToServer, 
                            ArrayList<String> listOfXMLFilesOnServer, 
                            ArrayList<String> filesInUpdateDirectory, 
                            ArrayList<String> justNamesOfFilesInUpdateDirectory,
                            ArrayList<String> justNamesOfFilesOnServer,
                            ArrayList<Date> datesOfFilesInUpdateDirectory,
                            ArrayList<Date> datesOfXMLFiles)
    {
        ArrayList<String> filesToBeDownloaded = new ArrayList<String>();
        ArrayList<String> filesToBeDeleted = new ArrayList<String>();
        
        
        for(int i = 0; i < listOfXMLFilesOnServer.size(); i++)
        {
            if( filesInUpdateDirectory.indexOf( listOfXMLFilesOnServer.get(i) ) != -1 )
            {
                // do nothing
            }
            else
            {
                String currentXMLFileOnServer = justNamesOfFilesOnServer.get(i);
                int index = 0;
                if( (index = justNamesOfFilesInUpdateDirectory.indexOf(currentXMLFileOnServer)) != -1 ) 
                {
                    if(datesOfXMLFiles.get(i).after(datesOfFilesInUpdateDirectory.get(index))) // is the file from the server newer...
                    {
                        //System.out.println("file to be deleted: " + filesInUpdateDirectory.get(index)); // debug
                        //System.out.println("file to be downloaded: " + listOfXMLFilesOnServer.get(i));  // debug
                        filesToBeDeleted.add(filesInUpdateDirectory.get(index)); // add the old file to list of files to be deleted
                        filesToBeDownloaded.add(listOfXMLFilesOnServer.get(i));     
                    }
                }
                else // new XML file on server which does not exist locally
                {
                    //System.out.println("else occured"); // debug
                    //System.out.println(datesOfXMLFiles.get(i) + " and " + datesOfFilesInUpdateDirectory.get(index));
                    filesToBeDownloaded.add(listOfXMLFilesOnServer.get(i));
                }
                
            }
            
        }
        ArrayList<ArrayList<String>> filesToBeDownloadAndDeleted = new ArrayList<ArrayList<String>>();
        filesToBeDownloadAndDeleted.add(filesToBeDownloaded);
        filesToBeDownloadAndDeleted.add(filesToBeDeleted);
        //System.out.println("get: " + filesToBeDeleted.size());
        return filesToBeDownloadAndDeleted;
    }
    
    
    
}
